/*
 * OpenParts
 * A dynamic-loading components framework for GWT
 * Copyright (C) 2011 Christophe Bouthier  [chris{AT}binary-gastronome{DOT}fr]
 *
 * This work is partially based on work I have done at INRIA (http://www.inria.fr) 
 * in the context of the Qualipso European Project (http://qualipso.org/),
 * The work done at INRIA is Copyright (C) 2006-2011 INRIA
 *
 * This work is distributed under the LGPL version 3
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 3
 * as published by the Free Software Foundation. See the GNU
 * Lesser General Public License in LGPL.txt for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package fr.openparts.OpenParts.client;

import com.google.gwt.core.client.JavaScriptObject;

/**
 * Command abstract class, defining a command executed by {@link OPScheduler}.
 * 
 * @author Christophe Bouthier [chris{AT}binary-gastronome{DOT}fr]
 * @creation.date 09 November 2010
 */
public final class OPCommand extends JavaScriptObject {

    /**
     * Returns a command with the given type.
     * 
     * @param commandType
     *            the type of the command.
     * @param service
     *            the service necessary for this command. Can be the service containing the view, or the service to load for example. Can be null if no service
     *            is necessary (for example for a message from a slot to its view).
     * @param params
     *            parameters of the command, if any. Can be null.
     * @param callback
     *            the callback to call when the command is executed either successfully or failing. Can be null.
     * @return the command itself. Cannot be null.
     */
    public static final OPCommand commandFactory(final int commandType, final String service, final OPParams params, final OPCommandCallback callback) {
        OPParamsJS paramsJS = null;
        if (params != null) {
            paramsJS = OPParamsJS.buildFromOPParams(params);
        }

        final OPCommand command = OPCommand.commandFactoryImpl(commandType, paramsJS);
        command.setService(service);
        command.setCallback(callback);

        return command;
    }

    /**
     * Real implementation of returning a command with the given type.
     * 
     * @param commandType
     *            the type of the command.
     * @param paramsJS
     *            parameters of the command, if any.
     * @return the command itself.
     */
    private static final native OPCommand commandFactoryImpl(final int commandType, final OPParamsJS paramsJS) /*-{
        var command = {};
        command.type = commandType;
        command.params = paramsJS;

        return command;
    }-*/;

    /**
     * Protected constructor, necessary because it's a JavaScriptObject.
     */
    protected OPCommand() {}

    /**
     * Set the service for this command. Can be null.
     * 
     * @param service
     *            the service name for this command. Can be null.
     */
    public final native void setService(final String service) /*-{
        this.service = service;
    }-*/;

    /**
     * Set the callback for this command, called when the command either finish successfully or fail. Can be null.
     * 
     * @param callback
     *            the callback for this command. Can be null.
     */
    public final void setCallback(final OPCommandCallback callback) {
        OPCommandCallbackCaller callbackCaller = null;
        if (callback != null) {
            callbackCaller = new OPCommandCallbackCaller(callback);
        }

        setCallbackImpl(callbackCaller);
    }

    /**
     * Real implementation of setting the callback for this command, called when the command either finish successfully or fail. Can be null.
     * 
     * @param callback
     *            the callback for this command. Can be null.
     */
    private final native void setCallbackImpl(final OPCommandCallbackCaller callback) /*-{
        if (callback != null) {
           this.callbackSuccess = function() {
               return $entry(callback.@fr.openparts.OpenParts.client.OPCommandCallbackCaller::onSuccess()());
           };
           this.callbackFail = function(reason) {
                return $entry(callback.@fr.openparts.OpenParts.client.OPCommandCallbackCaller::onFail(Lfr/openparts/OpenParts/client/OPCommandFailureReason;)(reason));
           };
        } else {
           this.callbackSuccess = null;
           this.callbackFail = null;
        }
    }-*/;

    /**
     * Returns the command type.
     * 
     * @return the command type.
     */
    public final native int getType() /*-{
        return this.type;
    }-*/;

    /**
     * Returns the service of which the command depends.
     * 
     * @return the service name. Can be null
     */
    public final native String getService() /*-{
        return this.service;
    }-*/;

    /**
     * Returns the parameters of the command.
     * 
     * @return the parameters of the command. Can be null.
     */
    public final OPParams getParams() {

        OPParams params = null;
        OPParamsJS paramsJS = getParamsJS();
        if (paramsJS != null) {
            params = paramsJS.toOPParams();
        }
        return params;
    };

    /**
     * Returns the js parameters of the command.
     * 
     * @return the js parameters of the command. Can be null.
     */
    private final native OPParamsJS getParamsJS() /*-{
        return this.params;
    }-*/;

    /**
     * Call the onSuccess callback. Don't do anything if there is no such callback.
     */
    public final native void onSuccess() /*-{
        if (this.callbackSuccess != null) {
            this.callbackSuccess();
        }
    }-*/;

    /**
     * Call the onFail callback. Don't do anything if there is no such callback.
     * 
     * @param reason
     *            the reason for the failure of the command
     */
    public final native void onFail(final OPCommandFailureReason reason) /*-{
        if (this.callbackFail != null) {
            this.callbackFail(reason);
        }
    }-*/;

}
